<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>射击小游戏</title>
    <style>
        .container {
            position: relative;
            width: 700px;
            height: 600px;
            margin: 40px auto;
            border: 1px solid red;
        }
        .game-ui {
            position: absolute;
            top: 200px;
            left: 60px;
            width: 400px;
        }
        .button {
            width: 100px;
            height: 30px;
            color: #fff;;
            background: #185da8;
            border: none;
            border-radius: 5px;
            outline: none;
        }
        .button:hover {
            background: #2083ee;
        }
        .game-start {
            display: block;
        }
        .game-over, .game-win {
            display: none;
        }
        .level {
            display: none;
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
        }
    </style>
</head>
<body>
    <div class="container">
        <div class="game-start game-ui">
            <h1 class="title">射击游戏</h1>
            <p class="game-desc">这是一个令人欲罢不能的射击游戏，使用 ← 和 → 操作你的飞机，使用空格（space）进行射击。一起来消灭宇宙怪兽吧！</p>
            <p class="game-level">当前Level: 1</p>
            <button class="js-play button">开始游戏</button>
        </div>

        <div class="game-over game-ui">
            <h1 class="title">射击游戏</h1>
            <p class="game-desc">游戏结束</p>
            <p class="game-level">当前Level: 1</p>
            <button class="js-play button">重新开始</button>
        </div>
        <div class="game-win game-ui">
            <h1 class="title">射击游戏</h1>
            <p class="game-desc">游戏通关</p>
            <p class="game-level">当前Level: 1</p>
            <button class="js-play button">重新开始</button>
        </div>
        <div class="level">Level: 1</div>

        <canvas id="canvas" width="700" height="600"></canvas>
    </div>
    <script>
        var CONFIG = {
                status: 'start', // 游戏开始默认为开始中
                level: 1, // 游戏默认等级
                totalLevel: 8, // 总共8关
                numPerLine: 10, // 游戏默认每行多少个怪兽
                canvasPadding: 30, // 默认画布的间隔
                bulletSize: 10, // 默认子弹长度
                bulletSpeed: 10, // 默认子弹的移动速度
                enemySpeed: 2, // 默认敌人移动距离
                enemySize: 30, // 默认敌人的尺寸
                enemyGap: 10,  // 默认敌人之间的间距
                enemyDirection: 'right', // 默认敌人一开始往右移动
                planeSpeed: 5, // 默认飞机每一步移动的距离
                planeSize: {
                    width: 60,
                    height: 100
                }, // 默认飞机的尺寸,
                };
        var startBtn = document.querySelectorAll('.js-play');
        
        var c = document.getElementById('canvas');
        var ctx = c.getContext('2d');

        var planeLocation = {x: 375-Math.floor(CONFIG.planeSize.width/2), y: 600-CONFIG.canvasPadding-CONFIG.planeSize.height};
        var enemyLocation = {};
        var bullet = [];

        startBtn.forEach(function(item) {
            item.addEventListener('click', function(e) {
                gameStart()
            })
        })
        function gameStart() {
            var game = document.querySelectorAll('.game-ui');
            game.forEach(function(item){
                item.style.display = 'none';
            })
            var level = document.querySelector('.level');
            level.innerHTML = 'Level：'+ CONFIG.level;
            level.style.display = 'block';
            ctx.clearRect(0,0,700,600);
            enemyLocation.x = [];
            enemyLocation.y =  CONFIG.canvasPadding;
            enemyLocation.z = [];

            var startX = 350 - Math.floor((CONFIG.enemySize+CONFIG.enemyGap)*CONFIG.numPerLine/2);
            for(var i=0; i<CONFIG.numPerLine; i++) {
                enemyLocation.x.push(startX+(i*(CONFIG.enemySize+CONFIG.enemyGap)))
                enemyLocation.z.push(1)
            }
            enemyLocation.y = CONFIG.canvasPadding;

            setTimeout(function(){
                level.style.display = 'none';
                CONFIG.status = 'start';
                window.requestAnimationFrame(refresh);
            },2000)
        }
        function gameOver() {
            var over = document.querySelector('.game-over .game-level');
            over.parentNode.style.display = 'block';
            over.innerHTML = '当前Level：'+ CONFIG.level;
            ctx.clearRect(0,0,700,600);
            CONFIG.level = 1;
            enemyLocation = {x: [],y: CONFIG.canvasPadding, z:[]};
        }
        function gameWin() {
            var over = document.querySelector('.game-win .game-level');
            over.parentNode.style.display = 'block';
            over.innerHTML = '当前Level：'+ CONFIG.level;
            ctx.clearRect(0,0,700,600);
            CONFIG.level = 1;
            enemyLocation = {x: [],y: CONFIG.canvasPadding, z:[]};
        }

        function drawPlane() {
            ctx.fillRect(planeLocation.x, planeLocation.y, CONFIG.planeSize.width,CONFIG.planeSize.height);
        }
        var count = 0;
        function drawEnemy() {
            for(var i=0; i<enemyLocation.x.length; i++) {
                if(enemyLocation.z[i]) {
                    ctx.fillRect(enemyLocation.x[i], enemyLocation.y, CONFIG.enemySize, CONFIG.enemySize);
                }
                if(CONFIG.enemyDirection=='right') {
                    enemyLocation.x[i] += CONFIG.enemySpeed*CONFIG.level;
                } else {
                    enemyLocation.x[i] -=  CONFIG.enemySpeed*CONFIG.level;
                }
            }
            if(enemyLocation.x[enemyLocation.x.length-1]>=700-CONFIG.canvasPadding-CONFIG.enemySize) {
                CONFIG.enemyDirection = 'left';
                count++;
                if(count%2===0) {
                    enemyLocation.y += CONFIG.enemySize;
                }
            } else if(enemyLocation.x[0] <= CONFIG.canvasPadding) {
                CONFIG.enemyDirection = 'right';
                count++;
                if(count%2===0) {
                    enemyLocation.y += CONFIG.enemySize;
                }
            }
            if(enemyLocation.y >= planeLocation.y-CONFIG.enemySize) {
                CONFIG.status = 'gameOver';
            }
        }
        // 刷新页面
        function refresh() {
            ctx.clearRect(0, 0,700, 600);
            drawEnemy();
            drawPlane();
            control();
            if(bullet.length) {
                drawBullet();
            }
            if(CONFIG.status==='start') {
                window.requestAnimationFrame(refresh)
            } else if(CONFIG.status === 'gameOver') {
                gameOver();
            } else if(CONFIG.status === 'next') {
                bullet = [];
                gameStart();
            } else if(CONFIG.status === 'win') {
                gameWin();
            }
            
        }
        // 子弹位置
        function bulletMove() {
            bullet.forEach(function(item, index) {
                item.y -= CONFIG.bulletSpeed;
                if(item.y<=CONFIG.canvasPadding) {
                    bullet.splice(index, 1);
                } else {
                    if(item.y<=enemyLocation.y+CONFIG.enemySize&&item.y>=enemyLocation.y) {
                        for(var i=0;i<enemyLocation.x.length;i++) {
                            if(item.x>=enemyLocation.x[i]&&item.x<=enemyLocation.x[i]+CONFIG.enemySize&&enemyLocation.z[i]) {
                                bullet.splice(index, 1);
                                enemyLocation.z[i] = 0
                                // 子弹击中目标后判断是否打完
                                judgeKill();
                                break;
                            }
                        }
                    }
                }
            })
        }
        // 画子弹
        function drawBullet() {
            bullet.forEach(function(item) {
                ctx.beginPath();
                ctx.moveTo(item.x, item.y);
                ctx.lineTo(item.x, item.y+CONFIG.bulletSize);
                ctx.strokeStyle="red";
                ctx.lineWidth = 3;
                ctx.stroke();
            })
            bulletMove()
        }
        // 监听键盘方向键
        // 左移
        function moveLeft() { 
            planeLocation.x -= CONFIG.planeSpeed;
                if(planeLocation.x<CONFIG.canvasPadding) {
                    planeLocation.x = CONFIG.canvasPadding;
                }
        }
        // 右移
        function moveRight() { 
            planeLocation.x += CONFIG.planeSpeed;
            if(planeLocation.x>700-CONFIG.planeSize.width-CONFIG.canvasPadding) {
                planeLocation.x = 700-CONFIG.planeSize.width-CONFIG.canvasPadding;
            }
        }
        
        // 发射
        function send() { 
            var obj = {x: planeLocation.x+Math.floor(CONFIG.planeSize.width/2), y: planeLocation.y - CONFIG.bulletSize };
            bullet.push(obj);
        }

        var keyArr = [false, false, false]; // 发射 左 右 无法同时监听两个按键

        // 控制
        function control() {
            keyArr.forEach(function(item, index) {
                if(index===0&&item) {
                    send();
                    keyArr[0] = false;
                } else if(index===1&&item) {
                    moveLeft();
                } else if(index===2&&item) {
                    moveRight();
                }
            })
        }
        document.addEventListener('keydown', function(e) {
            if(e.keyCode === 37) {
                keyArr[1] = true;
            }else if(e.keyCode === 39) {
                keyArr[2] = true;
            } else if(e.keyCode === 32){
                keyArr[0] = true;
            }
        })
        document.addEventListener('keyup', function(e) {
            if(e.keyCode === 37) {
                keyArr[1] = false;
            }else if(e.keyCode === 39) {
                keyArr[2] = false;
            } else if(e.keyCode === 32){
                keyArr[0] = false;
            }
        })

        // 敌人打完了进入下一关或通关
        function judgeKill() {
            
            if(enemyLocation.z.indexOf(1)===-1) {
                if(CONFIG.level===CONFIG.totalLevel) {
                    CONFIG.status = 'win';
                    alert('恭喜你,你通关了！')
                } else {
                    CONFIG.level++;
                    CONFIG.status = 'next';
                }
            }
        }
    </script>
</body>
</html>